package cn.edu.sjtu.se.dslab.component.data.util;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import cn.edu.sjtu.se.dslab.component.data.DataAttribute;
import cn.edu.sjtu.se.dslab.component.data.DataType;
import cn.edu.sjtu.se.dslab.component.data.DomainEntity;
import cn.edu.sjtu.se.dslab.component.data.Operation;
import cn.edu.sjtu.se.dslab.pojo.CodeGenerator;
import cn.edu.sjtu.se.dslab.service.IDataTypeService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.util.Const;
import cn.edu.sjtu.se.dslab.util.FileUtil;
import cn.edu.sjtu.se.dslab.util.Util;

@Service("dataComponentUtil")
public class DataComponentUtil extends CodeGenerator{
	
	@Resource(name = "domainEntityService")
	private IDomainEntityService domainEntityService;
	
	@Resource(name = "domainEntityGenerator")
	private DomainEntityGenerator domainEntityGenerator;
	
	@Resource(name = "dataTypeService")
	IDataTypeService dataTypeService;
	
	private final static String FILE_ID = "fileID";

	private final static String HEADER_LIST = "headerList";
	
	private final static String COUNT_LIST = "countList";
	
	private final static String AGGRAGATIOIN_LIST = "aggragationList";
	
	private final static String bus_data_templateFile = "bus_data.vm";
	
	public DataComponentUtil() {
		super();
	}
	
	public DataComponentUtil(String newTemplateFile) {
		super(newTemplateFile);
	}
	/**
	 * 生成总线数据区对应的全局变量，写入targetfile内
	 * @param idList
	 * @return
	 */
	public boolean generateBusData(List<Long> idList,String targetFile){
		//加载template
		template = ve.getTemplate(bus_data_templateFile);
		
		int index = targetFile.lastIndexOf("/");
		String fileName = targetFile.substring(index+1, targetFile.length());
		
		String fileId = fileName.replace(".", "_").toUpperCase();
		vc.put(FILE_ID, fileId);
		
		//生成头文件引用
		Set<String> headerList = new HashSet<String>();
		Set<DomainEntity> entities = new HashSet<DomainEntity>();
		for (int i = 0; i < idList.size(); i++) {
			entities.add(domainEntityService.getDomainEntityById(idList.get(i)));
		}
		System.out.println("size:"+entities.size());
		if (entities != null) {
			for (DomainEntity entity2:entities) {
				//默认文件名命名方式
				String temp = entity2.getName().replace(" ", "_").toLowerCase();
				headerList.add("#include \""+temp+".h\"");
			}
		}
		vc.put(HEADER_LIST,headerList);
		
		//组合项
		Set<String> aggEntityList = new HashSet<String>();
		Set<String> aggEntityCountList = new HashSet<String>();
		if (entities != null) {
			for (DomainEntity entity2:entities) {
				//默认struct 类型命名方式
				String type = Util.upperFirstLetter(entity2.getName().replace(" ", "_"));
					
				//默认struct 变量命名方式
				String id = Util.lowerrFirstLetter(entity2.getName().replace(" ", ""));
				//大小设置为10
				String countString = entity2.getName().replace(" ", "_").toUpperCase()+"_COUNT";
				aggEntityList.add(type+" "+id+"["+countString+"];");
				aggEntityCountList.add("#define "+countString+" 10");
			}
		}
		
		vc.put(AGGRAGATIOIN_LIST, aggEntityList);
		vc.put(COUNT_LIST, aggEntityCountList);
		
		FileWriter fWriter = null;
		try {
			File writeFile = getFile(targetFile);
			fWriter = new FileWriter(writeFile);
			if (template != null) {
				template.merge(vc, fWriter);
			}		
		} catch (IOException ex) {
			ex.printStackTrace();
			return false;
		} finally {
			try {
				fWriter.flush();
				fWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	/**
	 * 返回所有idlist对应的entity依赖的文件路径
	 * @param idList
	 * @return
	 */
	public List<String> getDependences(List<Long> idList)throws IOException{
		Map<Long, String> depMap = new HashMap<Long, String>();
		for (int i = 0; i < idList.size(); i++) {
			DomainEntity entity = domainEntityService.getDomainEntityById(idList.get(i));
			Map<Long, String> result = getDependence(entity);
			depMap.putAll(result);
		}
		return new ArrayList<String>(depMap.values());
	}
	
	/**
	 * 返回所有entity对应的依赖文件路径
	 * @param entity
	 * @return key->id，value->文件绝对路径
	 */
	public Map<Long, String> getDependence(DomainEntity entity)throws IOException{
		
		Set<DomainEntity> extendEntities = entity.getExtendsSet();
		Set<DomainEntity> aggragationEntities = entity.getAggregations();
		Set<DomainEntity> dependEntities = entity.getDepends();
		Map<Long, String> depMap = new HashMap<Long, String>();
		
//		String fileName = Util.getEntityFileName(entity);
//		String filePath ="/WEB-INF/generate/entity/"+entity.getUri().split(":")[entity.getUri().split(":").length -1] + fileName;
//		String fileRealPath = request.getSession().getServletContext().getRealPath(filePath);
//		File file = new File(fileRealPath);
//		//如果entity对应的文件存在，即认为是最新的；每次修改entity，删除该文件（保证最新）
//		if (!file.exists()) {
//			DomainEntityGenerator generator = new DomainEntityGenerator();
//			generator.generateEntity(entity, fileRealPath);
//		}
//		if (!depMap.containsKey(entity.getId())) {
//			depMap.put(entity.getId(), filePath);
//		}
		Map<Long, String> res = generateDomainEntity(entity);
		depMap.putAll(res);
		
		if (extendEntities != null) {
			for (DomainEntity entity2:extendEntities) {
				//默认文件名命名方式
//				String temp = entity2.getName().replace(" ", "_").toLowerCase();
//				depMap.put(entity2.getId(), temp);
				if (!depMap.containsKey(entity2.getId())) {
					Map<Long, String> result = getDependence(entity2);
					depMap.putAll(result);
				}
			}
		}
		if (aggragationEntities != null) {
			for (DomainEntity entity2:aggragationEntities) {
				//默认文件名命名方式
//				String temp = entity2.getName().replace(" ", "_").toLowerCase();
//				depMap.put(entity2.getId(), temp);
				if (!depMap.containsKey(entity2.getId())) {
					Map<Long, String> result = getDependence(entity2);
					depMap.putAll(result);
				}
				
			}
		}
		if (dependEntities != null) {
			for (DomainEntity entity2:dependEntities) {
				//默认文件名命名方式
//				String temp = entity2.getName().replace(" ", "_").toLowerCase();
//				depMap.put(entity2.getId(), temp);
				if (!depMap.containsKey(entity2.getId())) {
					Map<Long, String> result = getDependence(entity2);
					depMap.putAll(result);
				}
			}
		}
		/******************************************将dataEntity的attribute和operation纳入依赖*******************************************/	
		Set<DataAttribute> attributes = entity.getAttributes();
		if (attributes!= null) {
			for (DataAttribute dataAttribute : attributes) {
				DomainEntity typeEntity = dataAttribute.getType();
				DataType tempType = dataTypeService.getDataTypeById(typeEntity.getId());
				System.out.println("attr type:"+typeEntity.getName());
				if ((tempType == null || !tempType.getCategory().equals(Const.DATA_TYPE_BASIC)) && !depMap.containsKey(typeEntity.getId())) {
					System.out.println("include dependence"+typeEntity.getName());
					Map<Long, String> result = getDependence(typeEntity);
					depMap.putAll(result);
				}
			}
		}
		Set<Operation> operations = entity.getOpertions();
		if (operations!= null) {
			for (Operation operation : operations) {
				DomainEntity returnEntity = operation.getInterfaceMethod().getReturnType();
				System.out.println("attr type:"+returnEntity.getName());
				DataType tempType = dataTypeService.getDataTypeById(returnEntity.getId());
				if ((tempType == null || !tempType.getCategory().equals(Const.DATA_TYPE_BASIC)) && !depMap.containsKey(returnEntity.getId())) {
					Map<Long, String> result = getDependence(returnEntity);
					depMap.putAll(result);
				}
				String depTypes = operation.getInterfaceMethod().getDepType();
				String type[] = depTypes.split(";");
				Set<String> tempSet = new HashSet<String>();
				for (String string : type) {
					if ("".equals(string)) continue;
					tempSet.add(string);
				}
				for (String string : tempSet){
					DomainEntity tempEntity =  domainEntityService.getDomainEntityById(Long.parseLong(string));
					DataType temp =  dataTypeService.getDataTypeById(Long.parseLong(string));
					if ((temp == null ||!temp.getCategory().equals(Const.DATA_TYPE_BASIC)) 
							&& !depMap.containsKey(tempEntity.getId())) {
						Map<Long, String> result = getDependence(tempEntity);
						depMap.putAll(result);
					}
				}
				
			}
		}
		return depMap;
	}
	
	/**
	 * 为当前entity生成代码，不考虑依赖，组合和继承
	 * @param entity
	 * @return
	 */
	private Map<Long, String> generateDomainEntity(DomainEntity entity){
		Map<Long, String> depMap = new HashMap<Long, String>();
		String fileName = Util.getEntityFileName(entity);
		/**
		 * 仅仅对于领域实体有用
		 */
		String implName = Util.getEntityImplFileName(entity);
		
		String filePath =Const.DOMAIN_ENTITY_GENERATE_PATH+entity.getUri().split(":")[entity.getUri().split(":").length -1] + "/"+fileName;
		//String fileRealPath = Const.ABSOLUTE_GENERATE_PATH+filePath;
		String fileRealPath = FileUtil.getRootPath() + "generate/" + filePath;
		
		File file = new File(fileRealPath);
		//如果entity对应的文件存在，即认为是最新的；每次修改entity，删除该文件（保证最新）
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		DataType tempType = dataTypeService.getDataTypeById(entity.getId());
		if (tempType != null && tempType.getCategory().equals(Const.DATA_TYPE_ENUM)) {
			domainEntityGenerator.generateDataType(tempType, fileRealPath);
			System.out.println("generate data type enmu");
		}else {
			domainEntityGenerator.generateEntity(entity, fileRealPath);
			if (entity.getOpertions() != null && entity.getOpertions().size()>0) {
				String implFilePath = FileUtil.getRootPath() + "generate/" +Const.DOMAIN_ENTITY_GENERATE_PATH+entity.getUri().split(":")[entity.getUri().split(":").length -1] + "/"+ implName;
				domainEntityGenerator.generateEntityImplFile(entity,implFilePath);
				depMap.put(0 - entity.getId(), implFilePath);
			}
		}
		depMap.put(entity.getId(), fileRealPath);
		return depMap;
	}
	
	
	
	/**
	 * 为当前entity生成代码(对于dataentity，如果有实现代码，两个文件名用；号隔开)
	 * @param entity
	 * @return
	 */
	public String generateDomainEntityFile(DomainEntity entity){
		StringBuffer result = new StringBuffer();
		String fileName = Util.getEntityFileName(entity);
		/**
		 * 仅仅对于领域实体有用
		 */
		String implName = Util.getEntityImplFileName(entity);
		
		String filePath = Const.DOMAIN_ENTITY_GENERATE_PATH+entity.getUri().split(":")[entity.getUri().split(":").length -1] + "/"+fileName;
		//String fileRealPath = Const.ABSOLUTE_GENERATE_PATH+filePath;
		String fileRealPath = FileUtil.getRootPath() + "generate/" + filePath;
		
		File file = new File(fileRealPath);
		//如果entity对应的文件存在，即认为是最新的；每次修改entity，删除该文件（保证最新）
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
		DataType tempType = dataTypeService.getDataTypeById(entity.getId());
		if (tempType!= null && tempType.getCategory().equals(Const.DATA_TYPE_ENUM)) {
			domainEntityGenerator.generateDataType(tempType, fileRealPath);
		}else {
			domainEntityGenerator.generateEntity(entity, fileRealPath);
			result.append(filePath);
			if (entity.getOpertions() != null && entity.getOpertions().size()>0)  {
				String implFilePath = Const.DOMAIN_ENTITY_GENERATE_PATH+entity.getUri().split(":")[entity.getUri().split(":").length -1] + "/"+ implName;
				domainEntityGenerator.generateEntityImplFile(entity,FileUtil.getRootPath() + "generate/" +implFilePath);
				result.append(";");
				result.append(implFilePath);
			}
		}
		return result.toString();
	}
}

